package com.hundun.vision.biz.core;

import org.ta4j.core.Rule;
import org.ta4j.core.Strategy;
import org.ta4j.core.Trade;
import org.ta4j.core.Trade.TradeType;
import org.ta4j.core.TradingRecord;
import org.ta4j.core.rules.AndRule;
import org.ta4j.core.rules.OrRule;

import static org.ta4j.core.Trade.TradeType.BUY;
import static org.ta4j.core.Trade.TradeType.SELL;

/**
 * @author ：RuoChen
 * @date ：15:25 2024/12/6
 * @description：合约策略
 */

public class ContractStrategy implements Strategy {
    /**
     * 策略名称
     */
    private final String name;
    /**
     * 多单入场规则：建仓
     */
    private final ContractRule buyEntryRule;
    /**
     * 多单出场规则：止盈/止损
     */
    private final ContractRule buyExitRule;
    /**
     * 空单入场规则：建仓
     */
    private final ContractRule sellEntryRule;
    /**
     * 空单出场规则：止盈/止损
     */
    private final ContractRule sellExitRule;
    /**
     * 不稳定的K线数量
     */
    private int unstableBars = 0;

    public ContractStrategy(String name, ContractRule buyEntryRule, ContractRule buyExitRule, ContractRule sellEntryRule, ContractRule sellExitRule) {
        this.name = name;
        this.buyEntryRule = buyEntryRule;
        this.buyExitRule = buyExitRule;
        this.sellEntryRule = sellEntryRule;
        this.sellExitRule = sellExitRule;
    }

    public ContractStrategy(String name, ContractRule buyEntryRule, ContractRule buyExitRule, ContractRule sellEntryRule, ContractRule sellExitRule, int unstableBars) {
        this.name = name;
        this.buyEntryRule = buyEntryRule;
        this.buyExitRule = buyExitRule;
        this.sellEntryRule = sellEntryRule;
        this.sellExitRule = sellExitRule;
        this.unstableBars = unstableBars;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public Rule getEntryRule() {
        return null;
    }

    @Override
    public Rule getExitRule() {
        return null;
    }

    /**
     * 获取命中的入场规则
     *
     * @param index         当前索引
     * @param tradingRecord 当前交易记录
     * @return 命中的 ContractRule 或 null
     */
    public ContractRule getEntryRule(int index, TradingRecord tradingRecord) {
        if (buyEntryRule.isSatisfied(index, tradingRecord)) {
            return buyEntryRule;
        } else if (sellEntryRule.isSatisfied(index, tradingRecord)) {
            return sellEntryRule;
        }
        return null;
    }

    /**
     * 获取命中的出场规则
     *
     * @param index         当前索引
     * @param tradingRecord 当前交易记录
     * @return 命中的 ContractRule 或 null
     */
    public ContractRule getExitRule(int index, TradingRecord tradingRecord) {
        if (tradingRecord == null) {
            return null;
        }
        Trade lastTrade = tradingRecord.getLastTrade();
        if (lastTrade == null) {
            return null;
        }
        TradeType tradeType = lastTrade.getType();
        if (BUY.equals(tradeType) && buyExitRule.isSatisfied(index, tradingRecord)) {
            return buyExitRule;
        } else if (SELL.equals(tradeType) && sellExitRule.isSatisfied(index, tradingRecord)) {
            return sellExitRule;
        }
//        if (buyExitRule.isSatisfied(index, tradingRecord)) {
//            return buyExitRule;
//        } else if (sellExitRule.isSatisfied(index, tradingRecord)) {
//            return sellExitRule;
//        }
        return null;
    }

    @Override
    public int getUnstableBars() {
        return unstableBars;
    }

    @Override
    public void setUnstableBars(int unstableBars) {
        this.unstableBars = unstableBars;
    }

    @Override
    public boolean isUnstableAt(int index) {
        return index < unstableBars;
    }

    @Override
    public boolean shouldEnter(int index, TradingRecord tradingRecord) {
        if (buyEntryRule.isSatisfied(index, tradingRecord)) {
            return true;
        } else if (sellEntryRule.isSatisfied(index, tradingRecord)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean shouldExit(int index, TradingRecord tradingRecord) {
        if (buyExitRule.isSatisfied(index, tradingRecord)) {
            return true;
        } else if (sellExitRule.isSatisfied(index, tradingRecord)) {
            return true;
        }
        return false;
    }

    @Override
    public Strategy and(Strategy strategy) {
        String andName = "and(" + name + "," + strategy.getName() + ")";
        Rule combinedEntry = new AndRule(this.getEntryRule(), strategy.getEntryRule());
        Rule combinedExit = new AndRule(this.getExitRule(), strategy.getExitRule());
        return new ContractStrategy(
                andName,
                new ContractRule(combinedEntry, true),
                new ContractRule(combinedExit, false),
                this.buyExitRule,
                this.sellExitRule);
    }

    @Override
    public Strategy or(Strategy strategy) {
        String orName = "or(" + name + "," + strategy.getName() + ")";
        Rule combinedEntry = new OrRule(this.getEntryRule(), strategy.getEntryRule());
        Rule combinedExit = new OrRule(this.getExitRule(), strategy.getExitRule());
        return new ContractStrategy(
                orName,
                new ContractRule(combinedEntry, true),
                new ContractRule(combinedExit, false),
                this.buyExitRule,
                this.sellExitRule);
    }

    @Override
    public Strategy opposite() {
        String oppositeName = "opposite(" + name + ")";
        return new ContractStrategy(oppositeName, this.sellEntryRule, this.buyEntryRule, this.sellExitRule, this.buyExitRule);
    }

    @Override
    public Strategy and(String name, Strategy strategy, int unstableBars) {
        String andName = "and(" + name + "," + strategy.getName() + ")";
        Rule combinedEntry = new AndRule(this.getEntryRule(), strategy.getEntryRule());
        Rule combinedExit = new AndRule(this.getExitRule(), strategy.getExitRule());
        return new ContractStrategy(andName, (ContractRule) combinedEntry, (ContractRule) combinedExit, this.buyExitRule, this.sellExitRule, unstableBars);
    }

    @Override
    public Strategy or(String name, Strategy strategy, int unstableBars) {
        String orName = "or(" + name + "," + strategy.getName() + ")";
        Rule combinedEntry = new OrRule(this.getEntryRule(), strategy.getEntryRule());
        Rule combinedExit = new OrRule(this.getExitRule(), strategy.getExitRule());
        return new ContractStrategy(orName, (ContractRule) combinedEntry, (ContractRule) combinedExit, this.buyExitRule, this.sellExitRule, unstableBars);
    }
}